#include<iostream>
#include<cstdlib>
#include<string>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<time.h>
#include<stdarg.h>

#define SIZE 1024
#define LOG_FILE "log.txt"

// 打印方式
#define Screen    1
#define OneFile   2
#define ClassFile 3

// 日志等级
#define Info    0
#define Debug   1
#define Warning 2
#define Error   3
#define Fatal   4


class Log
{
public:
    Log()
    :printMethod(Screen)
    ,path("./log/")
    {}
    ~Log()
    {}

    void Enable(int method)
    {
        printMethod = method;
    }

    std::string LevelToString(int level)
    {
        switch (level)
        {
        case Info:
            return "Info";
        case Debug:
            return "Debug";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            break;
        }
    }

    void PrintLog(int level, const std::string& logcontent)
    {
        switch (printMethod)
        {
        case Screen:
            std::cout<<logcontent<<std::endl;
            break;
        case OneFile:
            PrintOneFile(LOG_FILE, logcontent);
            break;
        case ClassFile:
            PrintClassFile(level, logcontent);
            break;
        default:
            break;
        }
    }

    void PrintOneFile(const std::string& filename, const std::string& logcontent)
    {
        const std::string path_name = path + filename;
        int fd = open(path_name.c_str(), O_WRONLY|O_CREAT|O_APPEND, 0666);
        if(fd < 0) return;
        write(fd, logcontent.c_str(), logcontent.size());
        close(fd);
    }

    void PrintClassFile(int level, const std::string& logcontent)
    {
        // "log.txt.Debug/Warning/Fatal"
        std::string filename = LOG_FILE;
        filename = + "." + LevelToString(level);
        PrintOneFile(filename, logcontent);
    }

    void operator()(int level, const char* format, ...)
    {
        time_t t = time(nullptr);
        struct tm* ctime = localtime(&t);
        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", LevelToString(level).c_str(),
            ctime->tm_year+1900, ctime->tm_mon+1, ctime->tm_mday, 
            ctime->tm_hour, ctime->tm_min, ctime->tm_sec);
        va_list s;
        va_start(s, format);

        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        va_end(s);

        char logcontent[2*SIZE];
        snprintf(logcontent, sizeof(logcontent), "%s %s", leftbuffer, rightbuffer);

        PrintLog(level, logcontent);
    }

private:
    int printMethod;
    std::string path;
};